﻿// Copyright 2013 Ronald Schlenker, www.technewlogic.de.
// 
// This file is part of Byond.
// 
// Byond is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
// 
// Byond is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with Byond.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Collections.Generic;
using System.Linq;

namespace Byond.Frontend
{
	class DocumentManager : IDocumentManager
	{
		private readonly IEnsembleQueryService _ensembleQueryService;
		private readonly Func<DocumentModelParams, DocumentModel> _modelFactory;
		private readonly EnsembleSerializer _ensembleSerializer;

		private readonly List<DocumentModel> _dirtyDocuments = new List<DocumentModel>();
		public IEnumerable<DocumentModel> DirtyDocuments { get { return _dirtyDocuments.ToList(); } }

		public event Action DirtyDocumentsChanged = () => { };
		public event Action<string> DocumentDiscarded = s => { };

		public DocumentModel TryGetDocumentFor(string path)
		{
			var cachedDocument = _dirtyDocuments.FirstOrDefault(
				it => it.FileName.Equals(path, StringComparison.InvariantCultureIgnoreCase));
			if (cachedDocument != null)
				return cachedDocument;

			var ensemble = _ensembleQueryService.TryGetByFileName(path);
			return ensemble == null 
				? null 
				: _modelFactory(new DocumentModelParams(path, ensemble.PatchCode, ensemble.UiCode));
		}

		public void SaveAll()
		{
			foreach (var dirtyDocument in DirtyDocuments.ToList())
				DoSaveDocument(dirtyDocument);

			DirtyDocumentsChanged();
		}

		public void Save(DocumentModel document)
		{
			DoSaveDocument(document);
			DirtyDocumentsChanged();
		}

		public void Discard(DocumentModel document)
		{
			_dirtyDocuments.Remove(document);
			DirtyDocumentsChanged();
			DocumentDiscarded(document.FileName);
		}

		public void MarkDirty(DocumentModel model)
		{
			if (!_dirtyDocuments.Contains(model))
			{
				if (_dirtyDocuments.Any(it => it.FileName == model.FileName))
					throw new Exception("Inconsisten document models.");

				_dirtyDocuments.Add(model);
				DirtyDocumentsChanged();
			}
		}

		private void DoSaveDocument(DocumentModel dirtyDocument)
		{
			_ensembleSerializer.Save(new Ensemble(
				dirtyDocument.FileName, dirtyDocument.PatchCode, dirtyDocument.UiCode));
			_dirtyDocuments.Remove(dirtyDocument);
		}
	}
}
